package com.hm.health.Fragment;

import android.os.Bundle;
import android.util.Log;
import android.view.View;

import com.github.mikephil.charting.data.Entry;
import com.goodix.fragment.BaseFragment;
import com.goodix.libromablecom.sdk.cardiff.arguments.GetArgumentsKeyEnum;
import com.goodix.utils.ToastUtils;
import com.goodix.view.LineCurveChartView;
import com.goodix.libromablecom.sdk.cardiff.CardiffConstants;
import com.goodix.comsdk.entity.MeasureResult;
import com.goodix.comsdk.sdk.OnHBDDataListener;
import com.goodix.libalgorithm.BaseLineFilter;
import com.goodix.libromablecom.sdk.cardiff.arguments.StartArgumentsKeyEnum;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.hm.health.MyApplication;
import com.hm.health.R;
import com.hm.health.Utils.Constans;
import com.hm.health.entity.CheckBoxProperty;
import com.hm.health.widget.CheckBoxPopWindow;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by chenshi on 2019/12/27.
 */

public class LineChartFragment extends BaseFragment {

    private static final String TAG = "CapLinesFragment";
    private static final int WAVE_FORM_TIME_INTERNEL = 25;
    private static final int WAVE_FORM_DISPLAY_DELAY = 100;

    private LineCurveChartView mLineCurveChartView;
    private ScheduledExecutorService mScheduledExecutorService;
    // [position][channel id]
    private int[][] mDataBuffer = new int[4000][256];
    private int mDataIndex = 0;
    private AtomicInteger mCount = new AtomicInteger(0);
    private List<CheckBoxProperty> mCheckBoxProperties;
    private String mFunctionName;
    private Map<Integer, BaseLineFilter> mBaseLineFilterMap = new HashMap<>();
    private boolean mEnableFilter = false;


    @Override
    public void onResume() {
        super.onResume();
        startDisplayTimer();
    }

    @Override
    public void onPause() {
        super.onPause();
        stopDisplayTimer();
    }


    @Override
    public void onDetach() {
        super.onDetach();
        Log.d(TAG, "onDetach: ");
        mDataBuffer = null;
    }

    @Override
    public void initView(View root, Bundle savedInstanceState) {
        for (CheckBoxProperty property : mCheckBoxProperties) {
            mLineCurveChartView.addLineDataSet(property.getText(), property.getColorChecked());
        }
        int sampleRate = Integer.decode(MyApplication.getHBDTestClient()
                .getRunTimeFlag(GetArgumentsKeyEnum.ARG_GET_SAMPLE_RATE));
        if (sampleRate <= 0) {
            if (mFunctionName.compareToIgnoreCase(StartArgumentsKeyEnum.AppFunction_ECG) == 0) {
                sampleRate = 500;
            } else {
                sampleRate = 25;
            }
        }

        mLineCurveChartView.setMaxVisibleValueCount(sampleRate * 3);
    }

    private void getDataAndDiaplayWaves() {
        synchronized (mCount) {
            Log.d(TAG, "getDataAndDiaplayWaves: ");
            if (!isAdded()) {
                return;
            }

            for (int index = 0; index < mCount.get(); index++) {
                int cnt = 0;
                for (CheckBoxProperty checkBoxProperty : mCheckBoxProperties) {
                    if (checkBoxProperty.isChecked()) {
                        int channelId = checkBoxProperty.getChannelId();
                        BaseLineFilter filter = mBaseLineFilterMap.get(channelId);
                        double result = mDataBuffer[index][channelId];
                        if ((channelId >= CardiffConstants.RawdataColumn.CH0.ordinal()
                                && channelId <= CardiffConstants.RawdataColumn.CH15.ordinal())
                                && mEnableFilter) {
                            result = filter.baseLineFilter(mDataBuffer[index][channelId]);
                        }
                        addDataToLine(cnt, mLineCurveChartView, (int) result);
                    } else {
                        mLineCurveChartView.clearData(cnt);
                    }
                    cnt++;
                }
            }
            mCount.set(0);
            mLineCurveChartView.refreshPlot();
        }
    }

    private void addDataToLine(int nChannel, LineCurveChartView chart, final int nPPG) {
        int nEntryCount = chart.getPPGLineDataSet(nChannel).getEntryCount();
        if (nEntryCount > chart.getMaxVisibleCount()) {
            chart.getPPGLineDataSet(nChannel).removeFirst();
        }
        Entry entry = new Entry(nPPG, mDataIndex++);
        chart.addEntry(nChannel, entry);
    }

    private void startDisplayTimer() {
        if (null == mScheduledExecutorService) {
            mScheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
            mScheduledExecutorService.scheduleAtFixedRate(() -> {
                getActivity().runOnUiThread(() -> getDataAndDiaplayWaves());
            }, WAVE_FORM_DISPLAY_DELAY, WAVE_FORM_TIME_INTERNEL, TimeUnit.MILLISECONDS);
        }

        MyApplication.getHBDTestClient().registerHBDDataListener(mOnHBDDataListener);
    }

    private void stopDisplayTimer() {
        Log.i(TAG, "stopDisplayTimer: ");
        if (null != mScheduledExecutorService) {
            mScheduledExecutorService.shutdownNow();
            mScheduledExecutorService = null;
        }
        MyApplication.getHBDTestClient().unRegisterHBDDataListener(mOnHBDDataListener);
    }

    @Override
    public int getCreateViewLayoutResId() {
        return R.layout.fragment_cap_lines;
    }

    @Override
    public void initData() {
        mFunctionName = getArguments().getString(Constans.ARGS_FUNCTION_NAME,
                StartArgumentsKeyEnum.AppFunction_HR);
        String jsonStr = getArguments().getString(Constans.ARGS_CHANNELS_NAME, "");
        mCheckBoxProperties = new Gson().fromJson(jsonStr, new TypeToken<List<CheckBoxProperty>>() {
        }.getType());
        if (null == mCheckBoxProperties) {
            ToastUtils.showShortToastMessage(getContext(), "mCheckBoxProperties is empty!");
            mCheckBoxProperties = new ArrayList<>();
        }

        int sampleRate = Integer.decode(MyApplication.getHBDTestClient()
                .getRunTimeFlag(GetArgumentsKeyEnum.ARG_GET_SAMPLE_RATE));
        if (sampleRate <= 0) sampleRate = 25;
        for (CheckBoxProperty p : mCheckBoxProperties) {
            BaseLineFilter filter = new BaseLineFilter();
            filter.startBaseLineFilter(sampleRate, false);
            mBaseLineFilterMap.put(p.getChannelId(), filter);
        }
    }

    @Override
    public void findView(View inflateView, Bundle savedInstanceState) {
        mLineCurveChartView = inflateView.findViewById(R.id.fragment_line_chart);
        inflateView.findViewById(R.id.image_add).setOnClickListener(mImageBtnAddListener);
    }

    View.OnClickListener mImageBtnAddListener = view -> {
        CheckBoxPopWindow popWindow = new CheckBoxPopWindow(getActivity(), view);
        popWindow.show(mEnableFilter, mCheckBoxProperties, new CheckBoxPopWindow.Callback() {
            @Override
            public void onCheckBoxPropertyChanged(boolean enableFilter, List<CheckBoxProperty> properties) {
                for (int i = 0; i < properties.size(); ++i) {
                    boolean state = properties.get(i).isChecked();
                    mCheckBoxProperties.get(i).setChecked(state);
                }
                mEnableFilter = enableFilter;
            }
        });
    };

    private OnHBDDataListener mOnHBDDataListener = new OnHBDDataListener() {
        @Override
        public void onDataChanged(String dataType, int[] dataArr) {
            Log.e(TAG, "onDataChanged, dataType = " + dataType + ", dataArr = " + Arrays.toString(dataArr));

            if (!isAdded()) {
                return;
            }

            synchronized (mCount) {
                if (mCount.get() >= mDataBuffer.length) {
                    mCount.set(0);
                }

                if (mFunctionName.equals(dataType)) {
                    for (int i = 0; i < dataArr.length; ++i) {
                        mDataBuffer[mCount.get()][i] = dataArr[i];
                    }
                    mCount.getAndAdd(1);
                }
            }
        }

        @Override
        public void onMeasureResult(MeasureResult result) {

        }
    };

    public static LineChartFragment newInstance(String functionName, List<CheckBoxProperty> checkBoxProperties) {
        LineChartFragment fragment = new LineChartFragment();
        Bundle bundle = new Bundle();
        bundle.putString(Constans.ARGS_FUNCTION_NAME, functionName);
        bundle.putString(Constans.ARGS_CHANNELS_NAME, new Gson().toJson(checkBoxProperties));
        fragment.setArguments(bundle);
        return fragment;
    }
}
